/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 *
 * Copyright @2008 the original author or authors.
 */
package com.bluestone.scripts;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import com.bluestone.util.Util;

/**
 * A project is the target of the test.
 * @author <a href="mailto:bluestone.daniel.q@gmail.com">daniel.q</a>
 * 
 */

@XmlRootElement(name="project")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "project", propOrder = {
	"browser",	
	"proxy",
	"properties",
    "resources",
    "presources",
    "inputs",
    "executes"
})
public class Project {
	
	@XmlAttribute
	private String projectId;
	
	@XmlAttribute
	private String name;
	
	@XmlAttribute
	private String version = "1.0";
	
	@XmlAttribute
	private String speedrate = "100";
	
	@XmlAttribute
	private String retrycount = "3";
	
	@XmlAttribute
	private String failurecount = "10";
	
	@XmlAttribute
	private String reportTemplate = "reports\\reportTemplate.jrxml";
	
	@XmlAttribute
	private String reportType="HTML";
	
	@XmlAttribute
	private String reportFile = "reports\\report.html";
	
	@XmlAttribute
	private String language = Locale.getDefault().getLanguage();
	
	@XmlAttribute
	private String country=Locale.getDefault().getCountry();
    
	@XmlElement(name = "browser")
	private Browser browser;
	
	@XmlElement(name = "proxy")
	private Proxy proxy;
	
	@XmlElement(name = "property")
	private List<Property> properties = null;
	
	@XmlElementWrapper(name = "resources")
	@XmlElement(name = "resource")
	private List<Resource> resources;
	
	@XmlElementWrapper(name = "presources")
	@XmlElement(name = "presource")
	private List<Resource> presources;	

	@XmlElementWrapper(name = "inputs")
	@XmlElement(name = "input")
	private List<Input> inputs;

	@XmlElementWrapper(name = "executes")
	@XmlElement(name = "execute")
	private List<Execute> executes;
	


	public Project(){
		this.projectId = Util.generateProjectId();
	}
	/**
	 * The project should be run under the browser.
	 * @return
	 */
	public Browser getBrowser() {
		return browser;
	}

	public void setBrowser(Browser browser) {
		this.browser = browser;
	}

	/**
	 * All of the TestSuites can be executed. 
	 * @return
	 */
	public List getExecutes() {
		return executes;
	}

	public void setExecutes(List executes) {
		this.executes = executes;
	}
	
	public void addExecute(Execute execute){
		if(this.executes == null){
			this.executes = new ArrayList();
		}
		this.executes.add(execute);
	}

	/**
	 * The name of the project.
	 * @return
	 */
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	/**
	 * The verdion of the project
	 * @return
	 */
	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public String toString() {
		String str = "project:";
		if (name != null) {
			str = str + "name=" + name;
		}
		if (version != null) {
			str = str + ",version=" + version;
		}
		if (speedrate != null) {
			str = str + ",speedrate=" + speedrate;
		}
		if (retrycount != null) {
			str = str + ",retrycount=" + retrycount;
		}
		if (failurecount != null) {
			str = str + ",failurecount=" + failurecount;
		}
		return (str);
	}

	/**
	 * All inputs of the project
	 * @return
	 */
	public List getInputs() {
		return inputs;
	}

	public void setInputs(List inputs) {
		this.inputs = inputs;
	}
	
	public void addInput(Input input){
		if(this.inputs==null){
			this.inputs = new ArrayList();
		}
		this.inputs.add(input);
	}

	/**
	 * The height of the browser titleBar.
	 * @return
	 */
	public int getTitlebarHeight() {
		return browser.getTitlebarHeight();
	}

	/**
	 * The height of the browser title,menu bar and the icon bar.
	 * @return
	 */
	public int getBarHeight() {
		return browser.getBarHeight();
	}

	/**
	 * Transfer the execute to TestSuite.
	 * @param execute
	 * @return TestSuite
	 */
	public TestSuite getTestSuite(Execute execute) {
		for (int i = 0; i < inputs.size(); i++) {
			Input input = (Input) inputs.get(i);			
			if (input.getFile().equalsIgnoreCase(execute.getFile())
					&& TestSuite.class.isInstance(input.getObject())) {
				return (TestSuite) input.getObject();
			}
		}
		return null;
	}

	/**
	 * According the path to find the Page.
	 * @param path
	 * @return Page
	 */
	public Page searchPage(String path) {
		Page page = null;
		for (int i = 0; i < inputs.size(); i++) {
			Input input = (Input) inputs.get(i);
			Page temp = input.searchPage(path);
			if (temp != null)
				return temp;
		}
		return page;
	}

	/**
	 * Accroding the path to find the Element.
	 * @param path
	 * @return Element
	 */
	public Element searchElement(String path) {
		Element element = null;
		for (int i = 0; i < inputs.size(); i++) {
			Input input = (Input) inputs.get(i);
			Element temp = input.searchElement(path);
			if (temp != null)
				return temp;
		}
		return element;
	}

	/**
	 * Accroding the path to find the Function.
	 * @param path
	 * @return Function
	 */
    public Function searchFunction(String path){
		for (int i = 0; i < inputs.size(); i++) {
			Input input = (Input) inputs.get(i);
			Function temp = input.searchFunction(path);
			if (temp != null)
				return temp;
		}
		return null;    	
    }
    /**
     * According the testCase path to find all of the actions.
     */
	public ArrayList getTestCaseActions(String path) {
		ArrayList list = new ArrayList();
		TestCase testcase = null;
		for (int i = 0; i < inputs.size(); i++) {
			Input input = (Input) inputs.get(i);
			testcase = input.searchTestCase(path);
			if (testcase != null) {
				ArrayList commands = (ArrayList)testcase.getCommands();
				for (int j = 0; j < commands.size(); j++) {
					Command command = (Command) commands.get(j);
					list.addAll(command.getActions());
				}
				break;
			}
		}
		return list;
	}

	/**
	 * According the command path to find all of the actions.
	 * @param path
	 * @return
	 */
	public ArrayList getCommandActions(ActionScript action) {
		Object cmd = action.getParent();
		if(Command.class.isInstance(cmd)){
			Object tc = ((Command)cmd).getParent();
			if(TestCase.class.isInstance(tc)){
				Object ts = ((TestCase)tc).getParent();
				if(TestSuite.class.isInstance(ts)){
					TestSuite testsuite = (TestSuite)ts;
					List testcases = testsuite.getTestcases();
					for(int i=0; i<testcases.size(); i++){
						TestCase testcase = (TestCase)testcases.get(i);
						List commands =testcase.getCommands();
						for(int j=0; j <commands.size(); j++){
							Command command = (Command)commands.get(j);
							if(action.getPara("value").equalsIgnoreCase(command.getName())){
								 return (ArrayList)command.getActions();
							}
						}
					}
				}
			}
		}
		return null;
	}

	/**
	 * The rate of the speed when exectue action.
	 * @return
	 */
	public String getSpeedrate() {
		return speedrate;
	}

	public void setSpeedrate(String speedrate) {
		this.speedrate = speedrate;
	}

	/**
	 * The failure count of the testCase in the project.
	 * @return
	 */
	public String getFailurecount() {
		return failurecount;
	}

	public void setFailurecount(String failurecount) {
		this.failurecount = failurecount;
	}

	/**
	 * The max retry times when testCase failure. 
	 * @return
	 */
	public String getRetrycount() {
		return retrycount;
	}

	public void setRetrycount(String retrycount) {
		this.retrycount = retrycount;
	}
	/**
	 * The unique id of the project.
	 * @return
	 */
	public String getProjectId(){
		return this.projectId;
	}

	/**
	 * The report file path.
	 * @return
	 */
	public String getReportFile() {
		return reportFile;
	}
	
	public void setReportFile(String reportFile) {
		this.reportFile = reportFile;
	}

	/**
	 * The report template file path.
	 * @return
	 */
	public String getReportTemplate() {
		return reportTemplate;
	}

	public void setReportTemplate(String reportTemplate) {
		this.reportTemplate = reportTemplate;
	}

	/**
	 * The report type, for example: HTML,PDF.
	 * @return
	 */
	public String getReportType() {
		return reportType;
	}

	public void setReportType(String reportType) {
		this.reportType = reportType;
	}

	/**
	 * Returns the country/region code for this locale, which will either be the empty string or an upercase ISO 3166 2-letter code. 
	 * @return
	 */
	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	/**
	 * Returns the language code for this locale, which will either be the empty string or a lowercase ISO 639 code.
	 * @return
	 */
	public String getLanguage() {
		return language;
	}

	public void setLanguage(String languange) {
		this.language = languange;
	}
	
	/**
	 * All of the proejct resources.
	 * @return
	 */
	public List getResources(){
		return this.resources;
	}
	
	public void addResource(Resource resource){
		if(this.resources==null){
			this.resources = new ArrayList();
		}
		this.resources.add(resource);
	}
	
	public void setResources(List resources){
		this.resources = resources;
	}
	
	/**
	 * A Locale object represents a specific geographical, political, or cultural region. 
	 * An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user.
	 * @return
	 */
	public Locale getLocale(){
		return new Locale(this.getLanguage(),this.getCountry());
	}
	public List getProperties() {
		return properties;
	}
	public void setProperties(List properties) {
		this.properties = properties;
	}
	
	public void putProperty(Property property){
		if(this.properties==null){
			this.properties = new ArrayList();
		}
		this.properties.add(property);
		Util.getLogger().info("add property file "+property.getName());
	}
	
	public void removeProperty(Property property){
		if(this.properties==null || property==null){
			return;
		}
		for(Property prop:properties){
			if(prop.getName().equalsIgnoreCase(property.getName())){
				properties.remove(prop);
				
				Util.getLogger().info("remove property file "+property.getName());
				break;
			}
		}
	}
	public Proxy getProxy() {
		return proxy;
	}
	public void setProxy(Proxy proxy) {
		this.proxy = proxy;
	}
}
